#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <CL/cl.h>
#include <string>
#include <malloc.h>

#define BILLION 1000000000

using namespace std;
extern const char ** createProgram(string, int *);
extern const char * createProgramBinary(string, size_t *);

int main(void){

    struct timespec start, afBuild, end;

    int psc = 0;
    const char **ps = createProgram("select.cl",&psc);

    clock_gettime(CLOCK_REALTIME,&start);

    cl_int error = 0;
    cl_device_id device;

    cl_uint numP;
    clGetPlatformIDs(0,NULL,&numP);

    cl_platform_id * pid = new cl_platform_id[numP];
    clGetPlatformIDs(numP, pid, NULL);

    clGetDeviceIDs(pid[0],CL_DEVICE_TYPE_GPU,1,&device,NULL);

    cl_context context = clCreateContext(0,1,&device,NULL,NULL,&error);
    if(error != CL_SUCCESS){
        printf("Error creating context\n");
        exit(-1);
    }

    cl_command_queue_properties prop = 0;
    prop |= CL_QUEUE_PROFILING_ENABLE;

    cl_command_queue queue = clCreateCommandQueue(context, device, prop, &error);
    if(error != CL_SUCCESS){
        printf("Error creating command queue\n");
        exit(-1);
    }

    cl_program program = clCreateProgramWithSource(context, psc, (const char **)ps, 0, 0);
    if(error != CL_SUCCESS){
        printf("Error creating program\n");
        exit(-1);
    }

    clBuildProgram(program, 0, 0 , 0 , 0, 0);
    if(error != CL_SUCCESS){
            printf("Error building program\n");
            exit(-1);
    }

    int tupleNum = 1024*1024*256;
    int * input = (int *)memalign(256,sizeof(int)*tupleNum);
    int * output = (int *)memalign(256,sizeof(int)*tupleNum);

    for(int i=0;i<tupleNum;i++){
        input[i] = i;
    }

    memset(output,0,sizeof(int)*tupleNum);

    cl_mem column = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(int)*tupleNum, NULL, &error);
    clEnqueueWriteBuffer(queue,column,CL_TRUE,0,sizeof(int)*tupleNum,input,0,0,0);

    cl_mem column1 = clCreateBuffer(context, CL_MEM_READ_WRITE|CL_MEM_ALLOC_HOST_PTR, sizeof(int)*tupleNum, NULL, &error);
    
    void* xx = clEnqueueMapBuffer(queue,column1,CL_TRUE,CL_MAP_WRITE|CL_MAP_READ,0,sizeof(int)*tupleNum,0,0,0,0);
    memcpy(xx,input,sizeof(int)*tupleNum);

    return 0;
}


